package service

import (
	"fmt"
	"github.com/StackExchange/wmi"
	"miao-wails/backed/lib/utils"
	"miao-wails/backed/structs/idp"
	"os"
	"strings"
)

func (s idpService) getSysInfo() (out idp.Sys, err error) {
	var (
		hostname string
		sysAbs   SystemAbstract
		opeSys   OperatingSystem
	)
	hostname, err = os.Hostname()
	if err != nil {
		return
	}
	sysAbs, err = s.getSystemAbstract()
	if err != nil {
		return
	}
	opeSys, err = s.getOperatingSystem()
	if err != nil {
		return
	}
	out = idp.Sys{
		HostName:  hostname,
		OsName:    opeSys.Caption,
		OsVersion: opeSys.BuildNumber,
		Kernel:    sysAbs.SystemType,
		Arch:      opeSys.OSArchitecture,
		Vendor:    sysAbs.Manufacturer,
		Product:   sysAbs.Model,
		Serial:    opeSys.SerialNumber,
	}
	return
}

type SystemAbstract struct {
	DNSHostName               string // eg:hcy ,机器名
	Domain                    string // eg:WORKGROUP, 域
	Manufacturer              string // eg:HASEE Computer ,制造商
	Model                     string // eg:H310CM ,型号
	Name                      string // eg：hcy，名称
	NumberOfLogicalProcessors uint32 // eg:6, 逻辑处理器数量
	NumberOfProcessors        uint32 // eg:1 ,物理处理器数量
	PartOfDomain              bool   // eg:false, 计算机是否入域
	SystemType                string // eg；x64-based PC ，系统类
}

func (s idpService) getSystemAbstract() (out SystemAbstract, err error) {
	data := make([]SystemAbstract, 0)
	err = wmi.Query("select * from Win32_ComputerSystem", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_ComputerSystem err")
		return
	}
	out = data[0]
	return
}

type OperatingSystem struct {
	BuildNumber            string // eg : 19043 .操作系统的构建号,它比产品发布版本号更精确的版本信息。
	Caption                string // eg:Microsoft Windows 10 专业版 , 系统标题
	CountryCode            string // eg:86 ,操作系统使用的国家或者区域代码
	CSName                 string // eg:HCY , 计算机名
	CurrentTimeZone        uint16 // eg:480，基于格林威治时间需要修正的时间差
	Description            string // eg:hechongyang ,系统描述
	Distributed            bool   // eg：false ，该计算机是否为一个分布式系统的节点
	InstallDate            string // eg: 20210207150436.000000+480 ,// 操作系统安装时间
	LastBootUpTime         string // eg:20210811202542.462934+480 ,//操作系统最后一次重启的日期和时间。就是点重启
	LocalDateTime          string // eg:20210929164244.818000+480 ,// 操作系统最后一次的启动时间
	Manufacturer           string // eg:Microsoft Corporation ,系统生产商
	MaxNumberOfProcesses   uint32 // eg: 4294967295 ，系统允许分配的最大进程数
	MaxProcessMemorySize   uint64 // eg:137438953344 ，系统允许分配给进程的最大内存空间，单位kb。在非虚拟机上，这个空间通常 = 总内存空间-（bios+操作系统）
	Name                   string // eg: Microsoft Windows 10 专业版|C:\WINDOWS|\Device\Harddisk1\Partition4 ,系统名称
	NumberOfProcesses      uint32 // eg:249 ,当前在系统上运行的进程数量
	NumberOfUsers          uint32 // eg:2, 操作系统当前为其存储状态信息的用户会话数。
	OSArchitecture         string // eg: 64位 ，操作系统位数
	Primary                bool   // eg:true ,当前操作系统是否位主系统，部分电脑可能存在双操作系统
	ProductType            uint32 // eg:1 ，系统附加信息，1-工作站，2-域控主机，3-服务器
	RegisteredUser         string //eg:rock ,操作系统注册用户名
	SerialNumber           string // eg:00330-80191-48344-AA161, 操作系统产品序列号。
	SystemDrive            string // eg:c； ，系统盘卷标
	TotalSwapSpaceSize     uint64 // eg:null ,交换分区的大小，linux上有这个设计，windows上一般都是null
	TotalVirtualMemorySize uint64 // eg:30077444 ，虚拟内存空间大小，单位kb
	TotalVisibleMemorySize uint64 // eg:16445956 ,物理内存空间大小，单位kb
	Version                string // eg:10.0.19043 ,系统版本号
	WindowsDirectory       string // eg:C:\WINDOWS ,系统安装的文件夹
}

func (s idpService) getOperatingSystem() (out OperatingSystem, err error) {
	data := make([]OperatingSystem, 0)
	err = wmi.Query("select * from Win32_OperatingSystem", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_OperatingSystem err")
		return
	}
	out = data[0]
	out.Name = strings.Split(out.Name, "|")[0]
	out.InstallDate = strings.Split(out.InstallDate, ".")[0]
	out.LastBootUpTime = strings.Split(out.LastBootUpTime, ".")[0]
	return
}

type CpuBaseInfo struct {
	//AssetTag string // eg：To Be Filled By O.E.M.,代表该处理器的资产标签。
	Description       string // eg:Intel64 Family 6 Model 158 Stepping 13 ,描述
	CurrentClockSpeed uint32 // eg:2901 ,-处理器的当前速度，以MHz为单位
	DataWidth         uint16 // eg :64 ,在32位处理器，该值是32，在64位处理器是64
	DeviceID          string // eg:cpu0,在系统上的处理器的唯一标识符
	//ExtClock                  uint32 // eg:100 , 外部时钟频率，以MHz为单位
	Family                    uint16 // eg:205 ,处理器系列类型
	L2CacheSize               uint32 // eg:1536 ,二级缓存大小,kb
	L3CacheSize               uint32 // eg:9216 ,三级缓存的大小,kb
	Manufacturer              string // eg:GenuineIntel,处理器的制造商
	MaxClockSpeed             uint32 // eg：2901，处理器的最大速度，以MHz为单位
	Name                      string // eg :Intel(R) Core(TM) i5-9400 CPU @ 2.90GHz 处理器的名称
	NumberOfCores             uint32 // eg:6,芯为处理器的当前实例的数目。核心是在集成电路上的物理处理器
	NumberOfLogicalProcessors uint32 // eg:6  ,用于处理器的当前实例逻辑处理器的数量
	ProcessorId               string // eg:"BFEBFBFF000906ED",描述处理器功能的处理器的信息,CPUID
	SystemName                string // eg :"HCY",系统的名称
}

func (s idpService) getCpu() (out idp.Cpu, err error) {
	data := make([]CpuBaseInfo, 0)
	err = wmi.Query("SELECT * FROM Win32_Processor", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_Processor err")
		return
	}
	out = idp.Cpu{
		Cpu:          data[0].Name,
		CpuCores:     int(data[0].NumberOfCores),
		CpuMhz:       fmt.Sprintf("%d MHz", data[0].MaxClockSpeed),
		CpuId:        data[0].ProcessorId,
		Manufacturer: data[0].Manufacturer,
	}
	return
}

type MemoryBaseInfo struct {
	Capacity     uint64 // eg:8589934592 ，获取内存容量, / 1024*1024*1024 才能换算成GB
	Description  string // eg:物理内存 ，物理内存还虚拟内存
	DataWidth    uint16 // eg：64，获取内存数据带宽
	Manufacturer string // eg：859B，生产商
	PartNumber   string // eg：CT8G4DFS8266.M8FE   ，零件编号,由生产商定义
	SerialNumber string // eg：2271E66A，编号
	Speed        uint32 // eg：2667，速率 内存频率 单位MHz
}

func (s idpService) getMemory() (out []idp.Memory, err error) {
	data := make([]MemoryBaseInfo, 0)
	err = wmi.Query("SELECT * FROM Win32_PhysicalMemory", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_PhysicalMemory err")
		return
	}
	out = make([]idp.Memory, 0)
	for i := range data {
		out = append(out, idp.Memory{
			SerialNumber: data[i].SerialNumber,
			Size:         data[i].Capacity,
			Mhz:          fmt.Sprintf("%d MHz", data[i].Speed),
			Manufacturer: data[i].Manufacturer,
		})
	}
	return
}

type LogicDiskInfo struct {
	Caption            string //  eg:C: ,标题，也就是盘符
	Description        string // eg:本地固定磁盘 ,描述
	DeviceID           string // eg:C: , 在系统中的唯一标识符
	DriveType          uint32 // eg:3 , 磁盘类型，0-未知；1-No Root Directory；2-移动磁盘；3-本地磁盘；4-网络驱动器；5-光盘；6-RAM盘
	FileSystem         string // eg:NTFS , 磁盘格式
	FreeSpace          uint64 // eg:88191721472,空闲空间
	Size               string // eg:255369482240 ,总空间
	SupportsDiskQuotas bool   // 是否支持磁盘配额
	VolumeName         string // eg: 软件，逻辑卷别名
	VolumeSerialNumber string // eg:2AF1A3B8 ,逻辑卷序列号，并非磁盘序列号。
}

func (s idpService) getDisk() (out []idp.LogicDisk, err error) {
	var data []LogicDiskInfo
	err = wmi.Query("SELECT * FROM Win32_LogicalDisk", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_LogicalDisk err")
		return
	}
	out = make([]idp.LogicDisk, 0)
	for i := range data {
		out = append(out, idp.LogicDisk{
			SerialNumber: data[i].VolumeSerialNumber,
			Total:        uint64(utils.StrToInt64(data[i].Size)),
			Used:         uint64(utils.StrToInt64(data[i].Size)) - data[i].FreeSpace,
			DeviceId:     data[i].DeviceID,
			FileSystem:   data[i].FileSystem,
		})
	}
	return
}

type DiskBaseInfo struct {
	BytesPerSector   uint32 // eg:512 ,在每个扇区的物理磁盘驱动器的字节数。
	Caption          string // eg:PCIe SSD ,对象的序列号
	Description      string // eg:磁盘驱动器 ,描述
	DeviceID         string // eg: \\.\PHYSICALDRIVE1 ,磁盘驱动器与系统中的其他设备的唯一标识符
	FirmwareRevision string // eg:E8FM11.6 ,修订制造商分配的磁盘驱动器固件。
	InterfaceType    string // eg:SCSI ,物理磁盘驱动器的类型 （IDE、sata）
	Manufacturer     string // eg:(标准磁盘驱动器) ,制造商名称
	MediaType        string // eg:Fixed hard disk media ,由该设备使用或访问的媒体类型。
	Model            string // eg；PCIe SSD ，磁盘驱动器的制造商的型号。
	Name             string // eg:\\.\PHYSICALDRIVE1 ,名字
	SerialNumber     string // eg:6479_A721_8068_6489. 由制造商分配的号来识别物理介质。
	Size             uint64 // eg:256052966400 ,磁盘大小 单位字节 / 1024*1024*1024 才能得到G，
	SystemName       string // eg：HCY ，系统名称
}

func (s idpService) getDiskSerialList() (out []string, err error) {
	var data []DiskBaseInfo
	err = wmi.Query("SELECT * FROM Win32_DiskDrive", &data)
	if err != nil {
		return
	}
	if len(data) == 0 {
		err = fmt.Errorf("call Win32_DiskDrive err")
		return
	}
	out = make([]string, 0)
	for index := range data {
		out = append(out, strings.TrimSpace(data[index].SerialNumber))
	}
	return
}

func (s idpService) getNetwork() (out idp.Network, err error) {
	var (
		ip  string
		mac string
	)
	ip, mac, err = s.getIpMAC()
	if err != nil {
		return
	}
	out = idp.Network{
		Ipv4: ip,
		Mac:  mac,
		Dns:  "todo",
	}
	return
}
